package com.liser.southernstar.app;

import android.app.Application;
import android.content.Intent;
import android.net.Uri;
import android.util.Log;

import androidx.core.content.FileProvider;

import com.liser.southernstar.exceptions.AppUpgradeException;
import com.liser.southernstar.net.Network;
import com.liser.southernstar.net.model.AppRestful;
import com.liser.southernstar.net.model.AppVersion;
import com.liser.southernstar.net.observer.SimpleSubs;
import com.liser.southernstar.utils.StreamUtils;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.concurrent.TimeUnit;

import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
import okhttp3.ResponseBody;


/**
 * APP升级助手
 *
 * @author Administrator
 * @date 2020/1/17 16:26
 */
public class AppUpgradeHelper {

    public static final String TAG = AppUpgradeHelper.class.getName();

    private Disposable disposable;

    /**
     * 时间间隔（默认10分钟）
     */
    private int period = 10;

    private TimeUnit unit = TimeUnit.MILLISECONDS;

    /**
     * apk的版本ID
     */
    private int versionCode;

    /**
     * apk的唯一标识
     */
    private String appKey;

    /**
     * APK下载后保存的目录
     */
    private String apkStoragePath;

    /**
     * 缓冲区大小
     */
    private int bufferSize = 1024 * 64;

    private String providerName;

    private Application application;

    public static AppUpgradeHelper get() {
        return AppUpdaterHolder.INSTANCE;
    }

    private static class AppUpdaterHolder {
        private static AppUpgradeHelper INSTANCE = new AppUpgradeHelper();
    }

    public AppUpgradeHelper time(int period, TimeUnit unit) {
        this.period = period;
        this.unit = unit;
        return this;
    }

    public AppUpgradeHelper apkVersion(int versionCode, String appKey) {
        this.versionCode = versionCode;
        this.appKey = appKey;
        return this;
    }

    public AppUpgradeHelper apkStoragePath(String apkStoragePath) {
        this.apkStoragePath = apkStoragePath;
        return this;
    }

    public AppUpgradeHelper bufferSize(int bufferSize) {
        this.bufferSize = bufferSize;
        return this;
    }

    public AppUpgradeHelper providerName(String providerName) {
        this.providerName = providerName;
        return this;
    }

    public AppUpgradeHelper application(Application application) {
        this.application = application;
        return this;
    }

    public void build() {
        Observable.interval(period, unit)
                .subscribeOn(Schedulers.io())
                .flatMap(number -> check())
                .filter(appRestful -> {
                    int code = appRestful.getCode();
                    if (0 != code) {
                        Log.e(TAG, "APP版本号检测出错：" + appRestful.getMsg());
                        return false;
                    } else {
                        return true;
                    }
                })
                .map(AppRestful::getData)
                .filter(appVersion -> {
                    Log.d(TAG, "本机APP版本号：" + versionCode + "服务器APP版本号：" + appVersion.getVersionCode());
                    if (versionCode == appVersion.getVersionCode()) {
                        return false;
                    } else {
                        return true;
                    }
                })
                .flatMap(appVersion -> Network.upgrade().downloadFile(appVersion.getDownloadUrl()))
                .map(ResponseBody::byteStream)
                .map(this::copyToLocal)
                .map(this::install)
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new SimpleSubs<Boolean>() {
                    @Override
                    public void onSubscribe(Disposable d) {
                        disposable = d;
                    }

                    @Override
                    public void onSuccess(Boolean b) {
                        Log.i(TAG, "APP下载完成启动安装程序...");
                    }

                    @Override
                    public void onError(Throwable e) {
                        Log.e(TAG, "APP版本升级出错：", e);
                        cancel(disposable);
                    }
                });
    }

    /**
     * 取消订阅
     */
    private void cancel(Disposable disposable) {
        if (disposable != null && !disposable.isDisposed()) {
            disposable.dispose();
        }
    }

    /**
     * 版本检查
     *
     * @return 订阅
     */
    private Observable<AppRestful<AppVersion>> check() {
        return Network.upgrade().checkVersion(versionCode, appKey);
    }

    /**
     * 存储到本地
     *
     * @param inputStream apk
     * @return 文件
     */
    private File copyToLocal(InputStream inputStream) {
        File file = new File(apkStoragePath);

        // 重新创建文件
        if (file.exists()) {
            boolean delete = file.delete();
            if (delete) {
                Log.d(TAG, "删除原APK文件：" + file.getPath());
            }
        } else {
            // 如果直接mkdirs，有些机型会把文件创建成为文件夹
            boolean mkdirs = new File(file.getParent()).mkdirs();
            if (mkdirs) {
                Log.d(TAG, "创建APK存储目录：" + file.getParent());
            }
        }

        // 复制文件到本地
        try (FileOutputStream out = new FileOutputStream(file)) {
            StreamUtils.fastCopy(inputStream, out, bufferSize);
        } catch (IOException e) {
            Log.e(TAG, "存储APK文件出错：", e);
            throw new AppUpgradeException("存储APK文件出错：", e);
        }

        return file;
    }

    private File copy(InputStream is) throws IOException {
        File file = new File(apkStoragePath);
        FileOutputStream fos = new FileOutputStream(file);
        BufferedInputStream bis = new BufferedInputStream(is);
        byte[] buffer = new byte[1024];
        int len;
        while ((len = bis.read(buffer)) != -1) {
            fos.write(buffer, 0, len);
        }
        fos.close();
        bis.close();
        is.close();
        return file;
    }

    /**
     * APK安装
     *
     * @param file apk文件
     * @return 无意义的返回值
     */
    private Boolean install(File file) {
        Intent intent = new Intent(Intent.ACTION_VIEW);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
        Uri uri = FileProvider.getUriForFile(application, providerName, file);
        intent.setDataAndType(uri, "application/vnd.android.package-archive");
        application.startActivity(intent);
        return true;
    }

}

